using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.IO;
using AUSRIS.Reports.Utilities.Deployment.Entities;
using AUSRIS.Reports.Utilities.Deployment.Logging;

namespace AUSRIS.Reports.Utilities.Deployment.FileSystem.CVSAdapter
{
    /// <summary>
    /// CVS based implementation of IRepository
    /// </summary>
	public class Repository : AbstractRepository
	{
		#region Private Fields

		private CVSInfo cvsInfo;

		#endregion

		#region Public Properties

		public CVSInfo CvsInfo
		{
			get
			{
				if ( this.cvsInfo == null )
				{
					throw new Exception("CVSInfo Property is null");
				}
				return cvsInfo;
			}
			set
			{
				cvsInfo = value;
			}
		}

		#endregion

		#region IRepository Members

		public override void CheckoutModule(string moduleName, string versionTag)
		{
			this.LogMessage("Killing CVS Processes");
			this.KillCVSProcesses();
			this.LogMessage("Clearing {0}", this.CvsInfo.WorkingFolder);
			this.ClearWorkingFolder();
			this.LogMessage("Checking out {0} ({1}) to {2}", moduleName, versionTag, this.CvsInfo.WorkingFolder);
			string arguments = String.Format("-d {0} checkout -P -r {1} -- {2}", this.CvsInfo.CvsRoot, versionTag, moduleName);
			this.cvsExec(arguments);
		}

		public override void Checkout(CatalogFile file, string versionTag)
		{
			string arguments = String.Format("-d {0} checkout -P -r {1} \"{2}\"", this.CvsInfo.CvsRoot, versionTag, file.SourcePath);
			this.cvsExec(arguments);
			string resultPath = this.GetLocalPath(file);
			if ( File.Exists(resultPath) )
			{
				this.LogMessage("File '{0}' Revision '{1}' checked out from CVS", Path.GetFileName(file.SourcePath), file.Revision);
			}
			else
			{
				throw new Exception(string.Format("ERROR: '{0}' version '{1}' was not checked out", file.Name, versionTag));
			}
		}

		/// <summary>
		/// Parses the Entries file in the CVS folder where the files was checked out for the Revision string.
		/// The lines in the Entries file are, for example: 
		/// 
		///		/Award Winners.rdl/1.1/Tue May 13 20:41:12 2008/-kb/TProduction
		/// 
		/// </summary>
		/// <param name="file"></param>
		public override void SetRevision(CatalogFile file)
		{
			file.SourcePath = this.GetLocalPath(file);
			if ( !File.Exists(file.SourcePath) )
			{
				throw new Exception(string.Format("ERROR: '{0}' does not exist", file.Name));
			}
			string parentDirectory = Path.GetDirectoryName(file.SourcePath);
			string entriesPath = Path.Combine(parentDirectory, Path.Combine("CVS", "Entries"));
			if ( !File.Exists(entriesPath) )
			{
				this.LogMessage("WARNING: {0} not found - Revision could not be determined", entriesPath);
			}
			string fileName = Path.GetFileName(file.SourcePath);
			string searchName = "/" + fileName;
			string[] allLines = File.ReadAllLines(entriesPath);
			foreach ( string line in allLines )
			{
				if ( line.StartsWith(searchName) )
				{
					string[] fields = line.Split('/');
					file.Revision = fields[2];
					return;
				}
			}
		}

		#endregion

        #region Overridden Protected Methods

        protected override string GetWorkingDirectory()
        {
            return this.CvsInfo.WorkingFolder;
        }

        #endregion

        #region Private Methods

        private void cvsExec(string arguments)
		{
			string command = String.Format("\"{0}\"", this.CvsInfo.ExePath);
			Process proc = new Process();
			proc.StartInfo.CreateNoWindow = true;
			//proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
			proc.StartInfo.WorkingDirectory = this.cvsInfo.WorkingFolder;
			proc.StartInfo.FileName = command;
			proc.StartInfo.Arguments = arguments;
			proc.Start();
			proc.WaitForExit();
		}

		private void KillCVSProcesses()
		{
			foreach ( Process runningProcess in Process.GetProcessesByName("cvs.exe") )
			{
				runningProcess.Kill();
			}
		}

		#endregion
	}
}